package com.fastwire.carriere.controller.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.mapper.CardBandwidthMapper;
import com.fastwire.carriere.common.mapper.NENameMapper;
import com.fastwire.carriere.common.mapper.TPNameMapper;
import com.fastwire.carriere.common.util.StringUtil;
import com.fastwire.carriere.controller.CrossConnectController;
import com.fastwire.carriere.controller.TerminationPointController;
import com.fastwire.carriere.controller.TopologicalLinkController;
import com.fastwire.carriere.dao.CrossConnectDao;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.NetworkInventoryDao;
import com.fastwire.carriere.dao.TopologicalLinkDao;
import com.fastwire.carriere.hibernate.daoimpl.NetworkInventoryDaoImpl;
import com.fastwire.carriere.inventory.entity.CrossConnect;
import com.fastwire.carriere.inventory.entity.FDFr;
import com.fastwire.carriere.inventory.entity.NetworkElement;
import com.fastwire.carriere.inventory.entity.NetworkEntityUserSpecificInfo;
import com.fastwire.carriere.inventory.entity.TopologicalLink;
import com.fastwire.carriere.inventory.vo.ConnectivityVo;
import com.fastwire.carriere.inventory.vo.TopologicalLinkVo;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class TopologicalLinkControllerImpl implements TopologicalLinkController {

	/** The t link dao. */
	private final TopologicalLinkDao tLinkDao = DAOFactory.getInstance()
			.getTopologicalLinkDao();

	private final NetworkInventoryDao inventoryDao = new NetworkInventoryDaoImpl();

	private final CrossConnectDao ccDao = DAOFactory.getInstance()
			.getCrossConnectDao();

	/**
	 * To connectivity vos.
	 * 
	 * @param tlList
	 *            the tl list
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	private List<ConnectivityVo> toConnectivityVos(
			Collection<TopologicalLink> tlList) throws DAOException {

		List<ConnectivityVo> connectivityVos = Lists.newArrayList();

		List<String> processedTLs = Lists.newArrayList();
		for (TopologicalLink topologicalLink : tlList) {

			if (!processedTLs.contains(topologicalLink.getName())) {
				processedTLs.add(topologicalLink.getName());
				NetworkElement aendNE = NENameMapper
						.getNEbyU2kName(topologicalLink.getAendTp().getName());

				NetworkElement zendNE = NENameMapper
						.getNEbyU2kName(topologicalLink.getZendTp().getName());

				ConnectivityVo conVo = new ConnectivityVo();
				/*
				 * if ("L2".equals(topologicalLink.getType())) { String
				 * utilization = getTLUtilization(aendNE,
				 * topologicalLink.getAendTp().getName());
				 * 
				 * if (utilization == null) { utilization =
				 * getTLUtilization(zendNE, topologicalLink
				 * .getZendTp().getName()); }
				 * 
				 * conVo.setUtilization(utilization);
				 * 
				 * }
				 */

				String aendTpString = TPNameMapper.getReadablePTPName(
						topologicalLink.getAendTp().getName(), aendNE);

				String zendTpString = TPNameMapper.getReadablePTPName(
						topologicalLink.getZendTp().getName(), zendNE);

				conVo.setName(topologicalLink.getEmsNativeName());
				conVo.setDirectionality(topologicalLink.getDirection());

				conVo.setAendTp(aendTpString);
				conVo.setZendTp(zendTpString);
				conVo.setBandwidthSetting(CardBandwidthMapper.getBandwidth(
						aendTpString, zendTpString));
				conVo.setaEnd(aendNE);
				conVo.setzEnd(zendNE);
				conVo.setType(topologicalLink.getType());
				conVo.setLayerRate(topologicalLink.getLayerRate());

				connectivityVos.add(conVo);
			}
		}

		return connectivityVos;
	}

	private String getTLUtilization(NetworkElement ne, String ptpFullName)
			throws DAOException {

		if (ne == null || StringUtil.isEmptyString(ptpFullName)) {
			return null;
		}

		String utilization = null;
		TerminationPointController tpController = new TerminationPointControllerImpl();
		List<CrossConnect> ccList = ccDao
				.getCrossConnectsbyPTPName(ptpFullName);

		int totalCCBandwidth = tpController.getTotalBandwidthOfPort(ccList);

		String readablePTPName = TPNameMapper.getReadablePTPName(ptpFullName,
				ne);

		String[] matchStrings = readablePTPName.split("-");

		if (matchStrings.length == 3)

			utilization = tpController.getPortUtilization(matchStrings[1],
					matchStrings[2], totalCCBandwidth);

		return utilization;

	}

	/**
	 * Gets the t lsby n es.
	 * 
	 * @param neList
	 *            the ne list
	 * @param hopNo
	 *            the hop no
	 * @return the t lsby n es
	 * @throws DAOException
	 *             the dAO exception
	 */
	private List<TopologicalLink> getTLsbyNEs(Set<String> neList, int hopNo)
			throws DAOException {

		Set<String> neSet = new TreeSet<String>();
		List<TopologicalLink> allTLList = new ArrayList<TopologicalLink>();
		TopologicalLinkDao tlDao = DAOFactory.getInstance()
				.getTopologicalLinkDao();

		if (!neList.isEmpty()) {

			List tlList = tlDao.findTLbyNESet(neList);
			allTLList.addAll(tlList);
			for (Object obj : tlList) {
				TopologicalLink currTopologicalLink = (TopologicalLink) obj;
				String aendNeID = NENameMapper
						.getNEIdbyName(currTopologicalLink.getAendTp()
								.getName());
				String zendNeID = NENameMapper
						.getNEIdbyName(currTopologicalLink.getZendTp()
								.getName());
				neSet.add(aendNeID);
				neSet.add(zendNeID);

			}

			neSet.removeAll(neList);

			if (--hopNo > 0) {
				allTLList.addAll(getTLsbyNEs(neSet, hopNo));
			}
		}

		return allTLList;

	}

	/**
	 * Gets the topological link graphby ne id and hops.
	 * 
	 * @param neId
	 *            the ne id
	 * @param hopNo
	 *            the hop no
	 * @return the topological link graphby ne id and hops
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<ConnectivityVo> getTopologicalLinkGraphbyNEIdAndHops(
			List<String> neIds, int hopNo) throws DAOException {
		Set<String> neSet = Sets.newHashSet();

		for (String neName : neIds) {
			NetworkElement ne = DAOFactory.getInstance().getNEDao()
					.findNEbyName(neName);
			neSet.add(ne.getName());
		}
		List<TopologicalLink> tlList = getTLsbyNEs(neSet, hopNo);
		LinkedHashMap<String, TopologicalLink> topologicalLinkMap = new LinkedHashMap<String, TopologicalLink>();

		for (TopologicalLink tl : tlList) {
			topologicalLinkMap.put(tl.getName(), tl);
		}
		return toConnectivityVos(topologicalLinkMap.values());

	}

	/**
	 * Group t lby slot and port.
	 * 
	 * @param neID
	 *            the ne id
	 * @return the hash multimap
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public HashMultimap<String, TopologicalLinkVo> groupTLbySlotAndPort(
			String neID) throws DAOException {

		List<String> neList = new ArrayList<String>();
		neList.add(neID);
		List<TopologicalLink> tlList = DAOFactory.getInstance()
				.getTopologicalLinkDao().findTLbyNEName(neID);

		HashMultimap<String, TopologicalLinkVo> tlslotMap = HashMultimap
				.create();

		for (TopologicalLink tl : tlList) {
			TopologicalLinkVo tlVo = new TopologicalLinkVo(tl);
			String endTP = (tl.getAendTp().getName().contains(neID)) ? tl
					.getAendTp().getName() : tl.getZendTp().getName();
			String endKey = TPNameMapper.getTPHashKey(endTP);
			if (!StringUtil.isEmptyString(endKey)) {
				tlslotMap.put(endKey, tlVo);
			}
		}

		return tlslotMap;

	}

	/**
	 * Gets the topological linksby ne id.
	 * 
	 * @param neId
	 *            the ne id
	 * @return the topological linksby ne id
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<TopologicalLinkVo> getTopologicalLinksbyNEId(String neId)
			throws DAOException {

		List<TopologicalLink> tlList = tLinkDao.findTLbyNEName(neId);

		List<TopologicalLinkVo> tlVos = Lists.newArrayList();

		for (TopologicalLink tl : tlList) {
			tlVos.add(new TopologicalLinkVo(tl));
		}

		return tlVos;
	}

	@Override
	public void updateTopologicalLink(TopologicalLinkVo tlVo)
			throws DAOException {

		NetworkEntityUserSpecificInfo neUserSpecificInfo = inventoryDao
				.getNetworkEntityUserSpecificInfobyNameAndType(
						tlVo.getNativeEmsName(),
						TopologicalLink.class.getSimpleName());

		if (neUserSpecificInfo == null) {
			neUserSpecificInfo = new NetworkEntityUserSpecificInfo();
			neUserSpecificInfo.setName(tlVo.getNativeEmsName());
			neUserSpecificInfo.setType(FDFr.class.getSimpleName());

		}

		neUserSpecificInfo.setRemark(tlVo.getRemarks());

		inventoryDao
				.saveOrUpdateNetworkEntityUserSpecificInfo(neUserSpecificInfo);

	}

	@Override
	public List<String> getTLUtilization(List<String> tlNames)
			throws DAOException {

		List<TopologicalLink> tls = tLinkDao
				.getTopologicalLinksbyNameSet(tlNames);

		List<String> utilizations = Lists.newArrayList();

		for (TopologicalLink topologicalLink : tls) {
			NetworkElement aendNE = NENameMapper.getNEbyU2kName(topologicalLink
					.getAendTp().getName());

			NetworkElement zendNE = NENameMapper.getNEbyU2kName(topologicalLink
					.getZendTp().getName());

			String utilization = getTLUtilization(aendNE, topologicalLink
					.getAendTp().getName());

			if (utilization == null) {
				utilization = getTLUtilization(zendNE, topologicalLink
						.getZendTp().getName());
			}

			utilizations.add(utilization);

		}

		return utilizations;

	}

	@Override
	public List<ConnectivityVo> getUtilizaingTunnels(List<String> tlNames)
			throws DAOException, ResourceException {

		List<TopologicalLink> tls = tLinkDao
				.getTopologicalLinksbyNameSet(tlNames);

		CrossConnectController ccController = new CrossConnectControllerImpl();

		List<ConnectivityVo> connectivityVos = Lists.newArrayList();

		for (TopologicalLink tl : tls) {
			String aendTp = tl.getAendTp().getName();
			String zendTp = tl.getZendTp().getName();
			List<CrossConnect> aendCcList = ccDao
					.getCrossConnectsbyPTPName(aendTp);

			List<CrossConnect> zendCcList = ccDao
					.getCrossConnectsbyPTPName(zendTp);

			Set<String> ccNames = getCommonTunnels(aendCcList, zendCcList);

			for (String ccName : ccNames) {
				connectivityVos.addAll(ccController.stitchTunnel(ccName));
			}

		}

		return connectivityVos;

	}

	private Set<String> getCommonTunnels(List<CrossConnect> aendCcList,
			List<CrossConnect> zendCcList) {
		Set<String> aendCCNames = Sets.newHashSet();

		for (CrossConnect cc : aendCcList) {
			aendCCNames.add(cc.getEmsNativeName());
		}

		Set<String> zendCCNames = Sets.newHashSet();

		for (CrossConnect cc : zendCcList) {
			zendCCNames.add(cc.getEmsNativeName());
		}

		aendCcList.retainAll(zendCcList);

		return aendCCNames;
	}

}
